/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hovercraft;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import org.netbeans.microedition.lcdui.WaitScreen;
import org.netbeans.microedition.util.SimpleCancellableTask;



/**
 * @author Witold Sowa, Krzysztof Goj
 */
public class HovercraftControl extends MIDlet implements CommandListener {


    private static final byte    LIFT_ENGINE_BIT = (1<<0);
    private static final byte          TRCTL_BIT = (1<<1);
    private static final byte        THRUST_BIT0 = (1<<2);
    private static final byte        THRUST_BIT1 = (1<<3);
    private static final byte          TURN_BIT0 = (1<<4);
    private static final byte          TURN_BIT1 = (1<<5);
    private static final byte          TURN_BIT2 = (1<<6);
    private static final byte TURN_DIRECTION_BIT = (byte)(1<<7);

    private static final byte DISCONNECT_COMMAND = (byte)0xF0;
    
    private static final byte THRUST_BITS_SHIFT = 2;
    private static final byte TURN_BITS_SHIFT = 4;

    public static final int MAXIMUM_SPEED = 3;

    private static final byte INITIAL_STATE = 0;

    private boolean midletPaused = false;
    private byte speed = 0;
    private byte rudderPos = 0;
    private byte rudderAngle = 0;
    public byte command;

    private Canvas controlCanvas = null;

    private byte hovercraftStatus = INITIAL_STATE;
    private int packageCount = 0;

    private static final String CONNECTION_ADDRESS = "btspp://00126F009F5B:1;authenticate=false;encrypt=false;master=false";

    private DataOutputStream btDOS;
    private DataInputStream btDIS;
    private StreamConnection btConn;
    boolean isConnected = false;


    public short pos0X=0, pos0Y=0, pos1X=0, pos1Y=0,
                 delta0X=0, delta0Y=0, delta1X=0, delta1Y=0,
                 flasgs1=0, flasgs2=0,
                 goodBytes0=0, badBytes0=0, goodBytes1=0, badBytes1=0;

    public byte getHovercraftStatusCode() {
        return hovercraftStatus;
    }

    public byte getHovercraftCommandCode() {
        return command;
    }

    public boolean isRudderTurning() {
        return (command & (TURN_BIT0 | TURN_BIT1 | TURN_BIT2)) != 0;
    }

    public boolean isSteeringTurningLeft() {
        return isRudderTurning() && ((command & TURN_DIRECTION_BIT) != 0);
    }

    public boolean isSteeringTurningRight() {
        return isRudderTurning() && !((command & TURN_DIRECTION_BIT) != 0);
    }
    
    public boolean isLiftEngineOn() {
        return (command & LIFT_ENGINE_BIT) != 0;
    }

    public boolean isThrustEngineOn() {
        return (command & (THRUST_BIT0 | THRUST_BIT1)) != 0;
    }

    public int getHovercraftSpeed() {
        return speed;
    }

    public int getPackageCount() {
        return packageCount;
    }

    public byte getRudderAngle() {
        return rudderAngle;
    }

    private void setCommandBit(byte pin) {
        command |= pin;
    }

    private void clearCommandBit(byte pin) {
        command &= ~pin;
    }

    public void turnLiftOn() {
        setCommandBit(LIFT_ENGINE_BIT);
        prepareCommandToSend();
    }

    public void turnLiftOff() {
        clearCommandBit(LIFT_ENGINE_BIT);
        prepareCommandToSend();
    }

    public void toggleLiftEngine() {
        if (isLiftEngineOn())
            turnLiftOff();
        else
            turnLiftOn();
    }

    private void prepareCommandToSend() {
        command &= ~(THRUST_BIT0 | THRUST_BIT1);
        command |= speed << THRUST_BITS_SHIFT;

        command &= ~(TURN_BIT0 | TURN_BIT1 | TURN_BIT2);
        command |= rudderPos << TURN_BITS_SHIFT;
        //sendCommand();
    }

    public void speedUp() {
        if (speed < MAXIMUM_SPEED)
            ++speed;
        prepareCommandToSend();
    }

    public void slowDown() {
        if (speed > 0)
            --speed;
        prepareCommandToSend();
    }

    public void turnLeft(byte turnPower) {
        rudderPos = turnPower;
        setCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void turnRight(byte turnPower) {
        rudderPos = turnPower;
        clearCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void goStraight() {
        rudderPos = 0;
        clearCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void startTurningLeft() {
        rudderPos = 4;
        setCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void startTurningRight() {
        rudderPos = 4;
        clearCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void stopTurning() {
        rudderPos = 0;
        setCommandBit(TURN_DIRECTION_BIT);
        prepareCommandToSend();
    }

    public void setControlCanvas(Canvas newCanvas) {
        controlCanvas = newCanvas;
    }

    private class CommunicationThread extends Thread {
        private static final long RESPONSE_TIMEOUT = 3000;
        private static final byte RESPONSE_PACKET_SIZE = 2;
        
        private int missingResponsesSoFar = 0;

        private synchronized void sendCommand() throws IOException {
            if(!isConnected)
                return;
            btDOS.writeByte(command);
            btDOS.flush();
        }

        private void processResponse(byte [] response) {
            if (rudderAngle != response[0]) {
                rudderAngle = response[0];
            }
            controlCanvas.repaint();
        }

        private synchronized void receiveResponse() throws IOException {
            long startTime = System.currentTimeMillis();
            short diff =-1;
            try {
                while (btDIS.available() < RESPONSE_PACKET_SIZE) {
                    sleep(1);
                    if (System.currentTimeMillis() - startTime > RESPONSE_TIMEOUT) {
                        throw new IOException();
                    }
                }
                diff = (short) (System.currentTimeMillis() - startTime);
            }
            catch (InterruptedException e) {
                return;
            }
            delta0X = diff;
            byte[] response = new byte[RESPONSE_PACKET_SIZE];
            while (btDIS.available()/RESPONSE_PACKET_SIZE > 0) {
                btDIS.read(response);
                packageCount++;
                processResponse(response);
            }
        }
        
        public void run() {
            while(isConnected) {
                try {
                    sendCommand();
                    receiveResponse();
                }
                catch (IOException e) {
                    onConnectionBroken();
                }
            }
        }
    }

    CommunicationThread communicationThread;

    public void disconnectBT() {
        try {
            isConnected = false;
            try {
                btDOS.writeByte(DISCONNECT_COMMAND);
                btDOS.flush();
                Thread.sleep(1000);
            }
            catch (Exception ex) { }
            btDOS.close();
            btDIS.close();
            btConn.close();
        }
        catch (Exception ex) { }
    }

    //<editor-fold defaultstate="collapsed" desc=" Generated Fields ">//GEN-BEGIN:|fields|0|
    private Command connectComand;
    private Command exitCommand;
    private Alert notConnectedAlert;
    private Form startScreen;
    private ImageItem imageItem;
    private Alert connectionBroken;
    private WaitScreen waitScreen;
    private Image coverImage;
    private SimpleCancellableTask connectByBT;
    //</editor-fold>//GEN-END:|fields|0|

    /**
     * The HelloMIDlet constructor.
     */
    public HovercraftControl() {
    }

    //<editor-fold defaultstate="collapsed" desc=" Generated Methods ">//GEN-BEGIN:|methods|0|
    //</editor-fold>//GEN-END:|methods|0|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: initialize ">//GEN-BEGIN:|0-initialize|0|0-preInitialize
    /**
     * Initilizes the application.
     * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method.
     */
    private void initialize() {//GEN-END:|0-initialize|0|0-preInitialize
        // write pre-initialize user code here
//GEN-LINE:|0-initialize|1|0-postInitialize
        // write post-initialize user code here
    }//GEN-BEGIN:|0-initialize|2|
    //</editor-fold>//GEN-END:|0-initialize|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: startMIDlet ">//GEN-BEGIN:|3-startMIDlet|0|3-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Started point.
     */
    public void startMIDlet() {//GEN-END:|3-startMIDlet|0|3-preAction
        // write pre-action user code here
        switchDisplayable(null, getStartScreen());//GEN-LINE:|3-startMIDlet|1|3-postAction
        // write post-action user code here
    }//GEN-BEGIN:|3-startMIDlet|2|
    //</editor-fold>//GEN-END:|3-startMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: resumeMIDlet ">//GEN-BEGIN:|4-resumeMIDlet|0|4-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Resumed point.
     */
    public void resumeMIDlet() {//GEN-END:|4-resumeMIDlet|0|4-preAction
        // write pre-action user code here
//GEN-LINE:|4-resumeMIDlet|1|4-postAction
        // write post-action user code here
    }//GEN-BEGIN:|4-resumeMIDlet|2|
    //</editor-fold>//GEN-END:|4-resumeMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: switchDisplayable ">//GEN-BEGIN:|5-switchDisplayable|0|5-preSwitch
    /**
     * Switches a current displayable in a display. The <code>display</code> instance is taken from <code>getDisplay</code> method. This method is used by all actions in the design for switching displayable.
     * @param alert the Alert which is temporarily set to the display; if <code>null</code>, then <code>nextDisplayable</code> is set immediately
     * @param nextDisplayable the Displayable to be set
     */
    public void switchDisplayable(Alert alert, Displayable nextDisplayable) {//GEN-END:|5-switchDisplayable|0|5-preSwitch
        // write pre-switch user code here
        Display display = getDisplay();//GEN-BEGIN:|5-switchDisplayable|1|5-postSwitch
        if (alert == null) {
            display.setCurrent(nextDisplayable);
        } else {
            display.setCurrent(alert, nextDisplayable);
        }//GEN-END:|5-switchDisplayable|1|5-postSwitch
        // write post-switch user code here
    }//GEN-BEGIN:|5-switchDisplayable|2|
    //</editor-fold>//GEN-END:|5-switchDisplayable|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: exitCommand ">//GEN-BEGIN:|134-getter|0|134-preInit
    /**
     * Returns an initiliazed instance of exitCommand component.
     * @return the initialized component instance
     */
    public Command getExitCommand() {
        if (exitCommand == null) {//GEN-END:|134-getter|0|134-preInit
            // write pre-init user code here
            exitCommand = new Command("Wyjd\u017A", Command.EXIT, 0);//GEN-LINE:|134-getter|1|134-postInit
            // write post-init user code here
        }//GEN-BEGIN:|134-getter|2|
        return exitCommand;
    }
    //</editor-fold>//GEN-END:|134-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: connectComand ">//GEN-BEGIN:|136-getter|0|136-preInit
    /**
     * Returns an initiliazed instance of connectComand component.
     * @return the initialized component instance
     */
    public Command getConnectComand() {
        if (connectComand == null) {//GEN-END:|136-getter|0|136-preInit
            // write pre-init user code here
            connectComand = new Command("Po\u0142\u0105cz", Command.ITEM, 0);//GEN-LINE:|136-getter|1|136-postInit
            // write post-init user code here
        }//GEN-BEGIN:|136-getter|2|
        return connectComand;
    }
    //</editor-fold>//GEN-END:|136-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">//GEN-BEGIN:|7-commandAction|0|7-preCommandAction
    /**
     * Called by a system to indicated that a command has been invoked on a particular displayable.
     * @param command the Command that was invoked
     * @param displayable the Displayable where the command was invoked
     */
    public void commandAction(Command command, Displayable displayable) {//GEN-END:|7-commandAction|0|7-preCommandAction
        // write pre-action user code here
        if (displayable == startScreen) {//GEN-BEGIN:|7-commandAction|1|137-preAction
            if (command == connectComand) {//GEN-END:|7-commandAction|1|137-preAction
                // write pre-action user code here
                switchDisplayable(null, getWaitScreen());//GEN-LINE:|7-commandAction|2|137-postAction
                // write post-action user code here
            } else if (command == exitCommand) {//GEN-LINE:|7-commandAction|3|135-preAction
                // write pre-action user code here
                exitMIDlet();//GEN-LINE:|7-commandAction|4|135-postAction
                // write post-action user code here
            }//GEN-BEGIN:|7-commandAction|5|120-preAction
        } else if (displayable == waitScreen) {
            if (command == WaitScreen.FAILURE_COMMAND) {//GEN-END:|7-commandAction|5|120-preAction
                // write pre-action user code here
                switchDisplayable(getNotConnectedAlert(), getStartScreen());//GEN-LINE:|7-commandAction|6|120-postAction
                // write post-action user code here
            } else if (command == WaitScreen.SUCCESS_COMMAND) {//GEN-LINE:|7-commandAction|7|119-preAction
                // write pre-action user code here
                showControls();//GEN-LINE:|7-commandAction|8|119-postAction
                // write post-action user code here
            }//GEN-BEGIN:|7-commandAction|9|7-postCommandAction
        }//GEN-END:|7-commandAction|9|7-postCommandAction
        // write post-action user code here
    }//GEN-BEGIN:|7-commandAction|10|
    //</editor-fold>//GEN-END:|7-commandAction|10|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: onControlsExit ">//GEN-BEGIN:|126-entry|0|127-preAction
    /**
     * Performs an action assigned to the onControlsExit entry-point.
     */
    public void onControlsExit() {//GEN-END:|126-entry|0|127-preAction
        if (isConnected) disconnectBT();
        // write pre-action user code here
        switchDisplayable(null, getStartScreen());//GEN-LINE:|126-entry|1|127-postAction
        // write post-action user code here
    }//GEN-BEGIN:|126-entry|2|
    //</editor-fold>//GEN-END:|126-entry|2|
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: connectByBT ">//GEN-BEGIN:|121-getter|0|121-preInit
    /**
     * Returns an initiliazed instance of connectByBT component.
     * @return the initialized component instance
     */
    public SimpleCancellableTask getConnectByBT() {
        if (connectByBT == null) {//GEN-END:|121-getter|0|121-preInit
            // write pre-init user code here
            connectByBT = new SimpleCancellableTask();//GEN-BEGIN:|121-getter|1|121-execute
            connectByBT.setExecutable(new org.netbeans.microedition.util.Executable() {
                public void execute() throws Exception {//GEN-END:|121-getter|1|121-execute
                    btConn = (StreamConnection)Connector.open(CONNECTION_ADDRESS);
                    btDOS = btConn.openDataOutputStream();
                    btDIS = btConn.openDataInputStream();
                    isConnected = true;
                    command = INITIAL_STATE;
                    communicationThread = new CommunicationThread();
                    communicationThread.start();

                }//GEN-BEGIN:|121-getter|2|121-postInit
            });//GEN-END:|121-getter|2|121-postInit
            // write post-init user code here
        }//GEN-BEGIN:|121-getter|3|
        return connectByBT;
    }
    //</editor-fold>//GEN-END:|121-getter|3|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: coverImage ">//GEN-BEGIN:|146-getter|0|146-preInit
    /**
     * Returns an initiliazed instance of coverImage component.
     * @return the initialized component instance
     */
    public Image getCoverImage() {
        if (coverImage == null) {//GEN-END:|146-getter|0|146-preInit
            // write pre-init user code here
            try {//GEN-BEGIN:|146-getter|1|146-@java.io.IOException
                coverImage = Image.createImage("/hovercraft/hc.jpg");
            } catch (java.io.IOException e) {//GEN-END:|146-getter|1|146-@java.io.IOException
                e.printStackTrace();
            }//GEN-LINE:|146-getter|2|146-postInit
            // write post-init user code here
        }//GEN-BEGIN:|146-getter|3|
        return coverImage;
    }
    //</editor-fold>//GEN-END:|146-getter|3|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: waitScreen ">//GEN-BEGIN:|118-getter|0|118-preInit
    /**
     * Returns an initiliazed instance of waitScreen component.
     * @return the initialized component instance
     */
    public WaitScreen getWaitScreen() {
        if (waitScreen == null) {//GEN-END:|118-getter|0|118-preInit
            // write pre-init user code here
            waitScreen = new WaitScreen(getDisplay());//GEN-BEGIN:|118-getter|1|118-postInit
            waitScreen.setTitle("Czekaj...");
            waitScreen.setCommandListener(this);
            waitScreen.setText("\u0141\u0105czenie z poduszkowcem...");
            waitScreen.setTask(getConnectByBT());//GEN-END:|118-getter|1|118-postInit
            // write post-init user code here
        }//GEN-BEGIN:|118-getter|2|
        return waitScreen;
    }
    //</editor-fold>//GEN-END:|118-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: startScreen ">//GEN-BEGIN:|133-getter|0|133-preInit
    /**
     * Returns an initiliazed instance of startScreen component.
     * @return the initialized component instance
     */
    public Form getStartScreen() {
        if (startScreen == null) {//GEN-END:|133-getter|0|133-preInit
            // write pre-init user code here
            startScreen = new Form("Poduszkowiec", new Item[] { getImageItem() });//GEN-BEGIN:|133-getter|1|133-postInit
            startScreen.addCommand(getExitCommand());
            startScreen.addCommand(getConnectComand());
            startScreen.setCommandListener(this);//GEN-END:|133-getter|1|133-postInit
            // write post-init user code here
        }//GEN-BEGIN:|133-getter|2|
        return startScreen;
    }
    //</editor-fold>//GEN-END:|133-getter|2|



    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: notConnectedAlert ">//GEN-BEGIN:|141-getter|0|141-preInit
    /**
     * Returns an initiliazed instance of notConnectedAlert component.
     * @return the initialized component instance
     */
    public Alert getNotConnectedAlert() {
        if (notConnectedAlert == null) {//GEN-END:|141-getter|0|141-preInit
            // write pre-init user code here
            notConnectedAlert = new Alert("B\u0142\u0105d", "Po\u0142\u0105czenie nie udane", null, null);//GEN-BEGIN:|141-getter|1|141-postInit
            notConnectedAlert.setTimeout(2000);//GEN-END:|141-getter|1|141-postInit
            // write post-init user code here
        }//GEN-BEGIN:|141-getter|2|
        return notConnectedAlert;
    }
    //</editor-fold>//GEN-END:|141-getter|2|
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: onConnectionBroken ">//GEN-BEGIN:|147-entry|0|148-preAction
    /**
     * Performs an action assigned to the onConnectionBroken entry-point.
     */
    public void onConnectionBroken() {//GEN-END:|147-entry|0|148-preAction
        if (isConnected) disconnectBT();
        // write pre-action user code here
        switchDisplayable(getConnectionBroken(), getStartScreen());//GEN-LINE:|147-entry|1|148-postAction
        // write post-action user code here
    }//GEN-BEGIN:|147-entry|2|
    //</editor-fold>//GEN-END:|147-entry|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: connectionBroken ">//GEN-BEGIN:|149-getter|0|149-preInit
    /**
     * Returns an initiliazed instance of connectionBroken component.
     * @return the initialized component instance
     */
    public Alert getConnectionBroken() {
        if (connectionBroken == null) {//GEN-END:|149-getter|0|149-preInit
            // write pre-init user code here
            connectionBroken = new Alert("B\u0142\u0105d", "Po\u0142\u0105czenie przerwane", null, null);//GEN-BEGIN:|149-getter|1|149-postInit
            connectionBroken.setTimeout(2000);//GEN-END:|149-getter|1|149-postInit
            // write post-init user code here
        }//GEN-BEGIN:|149-getter|2|
        return connectionBroken;
    }
    //</editor-fold>//GEN-END:|149-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: imageItem ">//GEN-BEGIN:|152-getter|0|152-preInit
    /**
     * Returns an initiliazed instance of imageItem component.
     * @return the initialized component instance
     */
    public ImageItem getImageItem() {
        if (imageItem == null) {//GEN-END:|152-getter|0|152-preInit
            // write pre-init user code here
            imageItem = new ImageItem("", getCoverImage(), ImageItem.LAYOUT_CENTER | Item.LAYOUT_TOP | Item.LAYOUT_BOTTOM | Item.LAYOUT_VCENTER | Item.LAYOUT_SHRINK | Item.LAYOUT_VSHRINK | Item.LAYOUT_EXPAND | Item.LAYOUT_VEXPAND | Item.LAYOUT_2, "<Missing Image>");//GEN-LINE:|152-getter|1|152-postInit
            // write post-init user code here
        }//GEN-BEGIN:|152-getter|2|
        return imageItem;
    }
    //</editor-fold>//GEN-END:|152-getter|2|

    public void showControls() {
        switchDisplayable(null, new ControlScreen(this));
    }

    /**
     * Returns a display instance.
     * @return the display instance.
     */
    public Display getDisplay () {
        return Display.getDisplay(this);
    }

    /**
     * Exits MIDlet.
     */
    public void exitMIDlet() {
        switchDisplayable (null, null);
        destroyApp(true);
        notifyDestroyed();
    }

    /**
     * Called when MIDlet is started.
     * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet.
     */
    public void startApp() {
        if (midletPaused) {
            resumeMIDlet ();
        } else {
            initialize ();
            startMIDlet ();
        }
        midletPaused = false;
    }

    /**
     * Called when MIDlet is paused.
     */
    public void pauseApp() {
        midletPaused = true;
    }

    /**
     * Called to signal the MIDlet to terminate.
     * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released.
     */
    public void destroyApp(boolean unconditional) {
    }
    
}
class ControlScreen extends Canvas implements CommandListener {
    static final int ARROWS_SPAN = 30;
    
    private int      currentSpeed = 0;
    private boolean       leftSet = false;
    private boolean      rightSet = false;
    private boolean         upSet = false;
    private boolean       downSet = false;

    private Image fan = null;
    private Image fanDisabled = null;
    private Image rudder = null;
    private Image leftRudderArrow = null;
    private Image leftRudderArrowDisabled = null;
    private Image rightRudderArrow = null;
    private Image rightRudderArrowDisabled = null;
    private Image[] thrustArrows = null;
    private Image wall = null;
    private Image wallDisabled = null;

    private Image    upArrow = null;
    private Image  downArrow = null;
    private Image  leftArrow = null;
    private Image rightArrow = null;
    private Image    upArrowHighlighted = null;
    private Image  downArrowHighlighted = null;
    private Image  leftArrowHighlighted = null;
    private Image rightArrowHighlighted = null;
    private String[] hovercraftSpeeds = {"stoi", "wolno", "średnio", "szybko"};

    
    private Command leaveControllsCommand = new Command("Wyjdź", Command.CANCEL, 1);
    private HovercraftControl mainMidlet;

    private Image getLiftFanImage() {
        if (mainMidlet.isLiftEngineOn())
            return fan;
        return fanDisabled;
    }

    private Image getRudderImage() {
        return rudder;
    }

    private Image getLeftRudderArrowImage() {
        if (mainMidlet.getRudderAngle()<0)
            return leftRudderArrow;
        return leftRudderArrowDisabled;
    }

    private Image getRightRudderArrowImage() {
        if (mainMidlet.getRudderAngle()>0)
            return rightRudderArrow;
        return rightRudderArrowDisabled;
    }

    private Image getThrustArrowsImage() {
        return thrustArrows[mainMidlet.getHovercraftSpeed()];
    }

    private Image getWallImage() {
        return wallDisabled;
    }

    private String getMidletDebugString() {
        return "";
    }

    private Image getLeftArrowImage() {
        if (leftSet)
            return leftArrowHighlighted;
        return leftArrow;
    }
    
    private Image getUpArrowImage() {
        if(upSet)
            return upArrowHighlighted;
        return upArrow;
    }

    private Image getRightArrowImage() {
        if(rightSet)
            return rightArrowHighlighted;
        return rightArrow;
    }

    private Image getDownArrowImage() {
        if(downSet)
            return downArrowHighlighted;
        return downArrow;
    }

    ControlScreen(HovercraftControl mainMidlet) {
        this.mainMidlet = mainMidlet;
        setCommandListener(this);
        addCommand(leaveControllsCommand);
        try {
            fan = Image.createImage("/hovercraft/fan.png");
            fanDisabled = Image.createImage("/hovercraft/fan_disabled.png");
            rudder = Image.createImage("/hovercraft/rudder.png");
            leftRudderArrow = Image.createImage("/hovercraft/left_rudder_arrow.png");
            leftRudderArrowDisabled = Image.createImage("/hovercraft/left_rudder_arrow_disabled.png");
            rightRudderArrow = Image.createImage("/hovercraft/right_rudder_arrow.png");
            rightRudderArrowDisabled = Image.createImage("/hovercraft/right_rudder_arrow_disabled.png");
            thrustArrows =  new Image[] {
                Image.createImage("/hovercraft/thrust_arrows_disabled.png"),
                Image.createImage("/hovercraft/thrust_arrows_1.png"),
                Image.createImage("/hovercraft/thrust_arrows_2.png"),
                Image.createImage("/hovercraft/thrust_arrows_3.png")
            };
            wall = Image.createImage("/hovercraft/wall.png");
            wallDisabled = Image.createImage("/hovercraft/wall_disabled.png");

            leftArrow = Image.createImage("/hovercraft/blue_left.png");
            upArrow = Image.createImage("/hovercraft/blue_up.png");
            rightArrow = Image.createImage("/hovercraft/blue_right.png");
            downArrow = Image.createImage("/hovercraft/blue_down.png");
            leftArrowHighlighted = Image.createImage("/hovercraft/red_left.png");
            upArrowHighlighted = Image.createImage("/hovercraft/red_up.png");
            rightArrowHighlighted = Image.createImage("/hovercraft/red_right.png");
            downArrowHighlighted = Image.createImage("/hovercraft/red_down.png");

            mainMidlet.setControlCanvas(this);
        }
        catch (IOException e) {
        }
    }

    protected void keyPressed(int keyCode) {
        int gameKeyCode = getGameAction(keyCode);
        
        switch (keyCode) {
            case Canvas.KEY_NUM5:
                mainMidlet.toggleLiftEngine();
                break;

            case Canvas.KEY_NUM8:
                downSet = true;
                currentSpeed = Math.max(0, currentSpeed - 1);
                mainMidlet.slowDown();
                break;

            case Canvas.KEY_NUM2:
                upSet = true;
                currentSpeed = Math.min(HovercraftControl.MAXIMUM_SPEED, currentSpeed + 1);
                mainMidlet.speedUp();
                break;

            case Canvas.KEY_NUM1:
                leftSet = true;
                mainMidlet.turnLeft((byte) 1);
                break;

            case Canvas.KEY_NUM4:
                leftSet = true;
                mainMidlet.turnLeft((byte) 2);
                break;

            case Canvas.KEY_NUM7:
                leftSet = true;
                mainMidlet.turnLeft((byte) 3);
                break;

            case Canvas.KEY_NUM3:
                rightSet = true;
                mainMidlet.turnRight((byte) 1);
                break;

            case Canvas.KEY_NUM6:
                rightSet = true;
                mainMidlet.turnRight((byte) 2);
                break;

            case Canvas.KEY_NUM9:
                rightSet = true;
                mainMidlet.turnRight((byte) 3);
                break;

            case Canvas.KEY_NUM0:
                mainMidlet.goStraight();
                break;

            case Canvas.KEY_STAR:
                leftSet = true;
                mainMidlet.startTurningLeft();
                break;

            case Canvas.KEY_POUND:
                rightSet = true;
                mainMidlet.startTurningRight();
                break;
        }

        repaint();
    }
    
    protected void keyReleased(int keyCode) {
        int gameKeyCode = getGameAction(keyCode);
        rightSet = leftSet = upSet = downSet = false;
        switch (keyCode) {
            case Canvas.KEY_NUM1:
            case Canvas.KEY_NUM4:
            case Canvas.KEY_NUM7:
            case Canvas.KEY_NUM3:
            case Canvas.KEY_NUM6:
            case Canvas.KEY_NUM9:
                mainMidlet.goStraight();
                break;
            case Canvas.KEY_POUND:
            case Canvas.KEY_STAR:
                mainMidlet.stopTurning();
                break;
        }
        repaint();
    }

    protected void paint(Graphics g) {
        int width = getWidth();
        int height = getHeight();
        int xCenter = width/2;
        int yArrowsBaseline = height/2+5;

        g.setColor(0xFF, 0xFF, 0xFF);
        g.fillRect(0, 0, width, height);
        g.setColor(0,0,0);

        g.drawImage(getUpArrowImage(),
                xCenter, yArrowsBaseline-ARROWS_SPAN,
                Graphics.VCENTER | Graphics.HCENTER);

        g.drawImage(getDownArrowImage(),
                xCenter, yArrowsBaseline+ARROWS_SPAN,
                Graphics.VCENTER | Graphics.HCENTER);

        g.drawImage(getLeftArrowImage(),
                xCenter-ARROWS_SPAN, yArrowsBaseline,
                Graphics.VCENTER | Graphics.HCENTER);

        g.drawImage(getRightArrowImage(),
                xCenter+ARROWS_SPAN, yArrowsBaseline,
                Graphics.VCENTER | Graphics.HCENTER);


        g.drawImage(getLiftFanImage(), 0, 0, Graphics.TOP | Graphics.LEFT);

        g.drawImage(getLeftRudderArrowImage(),
                (width-getRudderImage().getWidth())/2, 0,
                Graphics.TOP | Graphics.RIGHT);
        g.drawImage(getRudderImage(), width/2, 0, Graphics.TOP | Graphics.HCENTER);
        g.drawImage(getRightRudderArrowImage(),
                (width+getRudderImage().getWidth())/2, 0,
                Graphics.TOP | Graphics.LEFT);
        g.drawString(Math.abs(mainMidlet.getRudderAngle())+"°",
                width/2, getRudderImage().getHeight(),
                Graphics.TOP | Graphics.HCENTER);

        g.drawImage(getThrustArrowsImage(), width-5, 0, Graphics.TOP | Graphics.RIGHT);

        g.drawImage(getWallImage(), width*2/3, height, Graphics.BOTTOM | Graphics.HCENTER);

//        g.drawString(mainMidlet.pos0X+", "+mainMidlet.pos0Y+", \n"+
//                     mainMidlet.pos1X+", "+mainMidlet.pos1Y+", \n"+
//                     mainMidlet.badBytes0+", "+mainMidlet.badBytes1+", \n"+
//                     mainMidlet.goodBytes0+", "+mainMidlet.goodBytes1,
//                0, 0,
//                Graphics.LEFT | Graphics.TOP);

        g.drawString(mainMidlet.delta0X+", "+mainMidlet.delta0Y+", \n"+
//                     mainMidlet.delta1X+", "+mainMidlet.delta1Y+", \n"+
//                     mainMidlet.flasgs1+", "+mainMidlet.flasgs2+", \n"+
                     mainMidlet.getPackageCount(),
                0, height,
                Graphics.LEFT | Graphics.BOTTOM);
        
    }

    public void commandAction(Command command, Displayable disp) {
        if(command == leaveControllsCommand) {
            mainMidlet.onControlsExit();
        }
    }

}

